﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MediaInfoLib;
using System.Diagnostics;

namespace mkv2mp4
{
    public partial class MainForm : Form
    {
        private StreamReader reader;
        private string line;
        public MainForm()
        {
            InitializeComponent();

        }
        StringBuilder sb = new StringBuilder();
        private void InputText_TextChanged(object sender, EventArgs e)
        {
            int channal = 0;
            OutputText.Text = InputText.Text.Remove(InputText.Text.LastIndexOf(".")) + ".mp4";
            MediaInfo MI = new MediaInfo();
            MI.Open(InputText.Text);
            sb.Clear();
            comboBox1.Items.Clear();
            comboBox1.Text = "";

            channal = 0;
            sb.Append("Video\r\n");
            while (MI.Get(StreamKind.Video, channal, "Inform") != "")
            {
                sb.Append(MI.Get(StreamKind.Video, channal, "Inform") + "\r\n");
                channal++;
            }

            channal = 0;
            sb.Append("\r\nAudio\r\n");
            while (MI.Get(StreamKind.Audio, channal, "Inform") != "")
            {
                comboBox1.Items.Add("Ch. " + channal);
                sb.Append(MI.Get(StreamKind.Audio, channal, "Inform") + "\r\n");
                comboBox1.SelectedIndex = 0;
                channal++;
            }
            MI.Close();
            MediaInfo.Text = sb.ToString();
        }

        private void InputButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Matroska (*.mkv)|*.mkv|All file (*.*)|*.*";
            ofd.FilterIndex = 1;
            ofd.RestoreDirectory = true;
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                InputText.Text = ofd.FileName;
            }
        }

        private void InputText_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.All;
        }

        private void InputText_DragDrop(object sender, DragEventArgs e)
        {
            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
            InputText.Text = files[0];
        }

        private void OutputButton_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            sfd.Filter = "MPEG-4(*.mp4)|*.mp4|All file (*.*)|*.*";
            sfd.FilterIndex = 1;
            sfd.RestoreDirectory = true;
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                OutputText.Text = sfd.FileName;
            }
        }

        private void Start_Click(object sender, EventArgs e)
        {
            if (InputText.Text == "" && OutputText.Text == "")
            {
                MessageBox.Show("No input/output found.", "Error", MessageBoxButtons.OK);
                return;
            }
            if (File.Exists("foo.mp4")) { File.Delete("foo.mp4"); }
            if (File.Exists("foo.m4a")) { File.Delete("foo.m4a"); }
            if (File.Exists("foo.wav")) { File.Delete("foo.wav"); }
            if (File.Exists("foo.h264")) { File.Delete("foo.h264"); }
            /*if (File.Exists("tcv1.txt")) { File.Delete("tcv1.txt"); }
            if (File.Exists("tcv2.txt")) { File.Delete("tcv2.txt"); }*/
            MediaInfo MI = new MediaInfo();
            MI.Open(InputText.Text);
            if (MI.Get(StreamKind.Video, 0, "BitDepth") == "10")
                if (MessageBox.Show("位元深度=10", "Confirm Message", MessageBoxButtons.OKCancel) != DialogResult.OK)
                    return;
            String aType = MI.Get(StreamKind.Audio, 0, "Format").ToLowerInvariant();
            callVideo(InputText.Text);
            callAudio(InputText.Text, aType);
            /*if (aType == "flac" || aType == "wav" || aType == "vorbis")
            {
                AudioSelection asF = new AudioSelection();
                var result = asF.ShowDialog(this.Owner);
                if (result == DialogResult.OK)
                {
                    callQaa(asF.quality);
                    asF.Close();
                }
            }*/
            AudioSelection asF = new AudioSelection();
            var result = asF.ShowDialog(this.Owner);
            if (result == DialogResult.OK)
            {
                callQaa(asF.quality);
                asF.Close();
            }
            if (remuxer.Checked)
            {
                callmuxer();
                //callFFmpeg(OutputText.Text);
                callremuxer(OutputText.Text);
            }
            else
            {
                callMp4box(OutputText.Text);
            }
            /*if (File.Exists("foo.mp4")) { File.Delete("foo.mp4"); }
            if (File.Exists("foo.m4a")) { File.Delete("foo.m4a"); }
            if (File.Exists("foo.wav")) { File.Delete("foo.wav"); }
            if (File.Exists("foo.h264")) { File.Delete("foo.h264"); }
            if (File.Exists("tcv1.txt")) { File.Delete("tcv1.txt"); }
            if (File.Exists("tcv2.txt")) { File.Delete("tcv2.txt"); }*/
        }
        private void callAudio(String intput, String aType)
        {
            Process proc = new Process();
            ProcessStartInfo psi = proc.StartInfo;
            psi.FileName = "ffmpeg.exe";
            psi.CreateNoWindow = true;
            psi.RedirectStandardError = true;
            psi.UseShellExecute = false;
            switch (aType)
            {
                case "flac":
                case "wav":
                case "vorbis":
                    /*psi.Arguments = string.Format("-y -i \"{0}\" -vn -map a:{1} foo.wav", intput, comboBox1.SelectedIndex);
                    break;*/
                default:
                    //psi.Arguments = string.Format("-y -i \"{0}\" -vn -map a:{1} foo.m4a", intput, comboBox1.SelectedIndex);
                    psi.Arguments = string.Format("-y -i \"{0}\" -vn -map a:{1} foo.wav", intput, comboBox1.SelectedIndex);
                    break;
            }
            proc.Start();
            reader = proc.StandardError;
            while ((line = reader.ReadLine()) != null)
            {
                line += "\n";
                MediaInfo.Text += line;
            }
            proc.WaitForExit();
        }

        private void callVideo(String intput)
        {
            Process proc = new Process();
            ProcessStartInfo psi = proc.StartInfo;
            psi.FileName = "ffmpeg.exe";
            /*if (fpsCheckBox.Checked)
            {
                psi.Arguments = string.Format("-y -i \"{0}\" -an -c:v copy -bsf:v h264_mp4toannexb -r {1} foo.h264", intput, fpsComboBox.Text);
            }
            else
            {
                psi.Arguments = string.Format("-y -i \"{0}\" -an -c:v copy -bsf:v h264_mp4toannexb foo.h264", intput);
            }*/
            psi.Arguments = string.Format("-y -i \"{0}\" -an -c:v copy -bsf:v h264_mp4toannexb foo.h264", intput);
            /*if (fpsCheckBox.Checked)
            {
                psi.Arguments = string.Format("-y -i \"{0}\" -an -c:v copy -r {1} foo.mp4", intput, fpsComboBox.Text);
            }
            else
            {
                psi.Arguments = string.Format("-y -i \"{0}\" -an -c:v copy foo.mp4", intput);
            }*/
            psi.CreateNoWindow = true;
            psi.RedirectStandardError = true;
            psi.UseShellExecute = false;
            proc.Start();
            reader = proc.StandardError;
            while ((line = reader.ReadLine()) != null)
            {
                line += "\n";
                MediaInfo.Text += line;
            }
            proc.WaitForExit();
        }

        private void callQaa(int quality)
        {
            Process procQaa = new Process();
            ProcessStartInfo psiQaa = procQaa.StartInfo;
            psiQaa.FileName = "qaac";
            psiQaa.Arguments = string.Format("-i foo.wav --tvbr  \"{0}\"  -o foo.m4a", quality);
            psiQaa.RedirectStandardOutput = true;
            psiQaa.RedirectStandardError = true;
            psiQaa.UseShellExecute = false;
            psiQaa.CreateNoWindow = true;
            procQaa.Start();
            reader = procQaa.StandardError;
            while ((line = reader.ReadLine()) != null)
            {
                line += "\n";
                MediaInfo.Text += line;
            }
            procQaa.WaitForExit();
        }

        private void callMp4box(String output)
        {
            Process proc = new Process();
            ProcessStartInfo psi = proc.StartInfo;
            proc.StartInfo.FileName = "MP4Box";
            if (fpsCheckBox.Checked) { psi.Arguments = string.Format("-add foo.h264 -fps {1} -add foo.m4a \"{0}\"", output, fpsComboBox.Text); }
            else { psi.Arguments = string.Format("-add foo.h264 -add foo.m4a -new \"{0}\"", output); }
            proc.Start();
            proc.WaitForExit();
        }

        /*private void callFFmpeg(String output)
        {
            Process proc = new Process();
            ProcessStartInfo psi = proc.StartInfo;
            psi.FileName = "ffmpeg.exe";
            if (fpsCheckBox.Checked) { psi.Arguments = string.Format("-y -i foo.mp4  -i foo.m4a -c copy \"{0}\"", output); }
            else { psi.Arguments = string.Format("-y -i foo.mp4  -i foo.m4a -c copy \"{0}\"", output, fpsComboBox.Text); }
            psi.CreateNoWindow = true;
            psi.RedirectStandardError = true;
            psi.UseShellExecute = false;
            proc.Start();
            reader = proc.StandardError;
            while ((line = reader.ReadLine()) != null)
            {
                line += "\n";
                MediaInfo.Text += line;
            }
            proc.WaitForExit();
        }*/

        private void callmuxer()
       {
           Process proc = new Process();
           ProcessStartInfo psi = proc.StartInfo;
           String arguments = "";
           psi.RedirectStandardOutput = true;
           psi.RedirectStandardError = true;
           psi.UseShellExecute = false;
           psi.CreateNoWindow = true;
           proc.StartInfo.FileName = "muxer";
           if (fpsCheckBox.Checked) { arguments = string.Format("-i foo.h264?fps=\"{0}/{1}\" -o foo.mp4", Math.Round(Convert.ToDecimal(fpsComboBox.Text)) * 1000, "1001"); }
           else { arguments = string.Format("-i foo.h264 -o foo.mp4"); }
            
           //arguments = string.Format("-i foo.h264 -o foo.mp4");
           psi.Arguments = arguments;
           proc.Start();

           reader = proc.StandardError;
           while ((line = reader.ReadLine()) != null)
           {
               //line += "\n";
               MediaInfo.Text += line;
           }

           proc.WaitForExit();
       }

        private void callremuxer(String output)
        {
            Process proc = new Process();
            ProcessStartInfo psi = proc.StartInfo;
            String arguments = "";
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError = true;
            psi.UseShellExecute = false;
            psi.CreateNoWindow = true;
            proc.StartInfo.FileName = "remuxer";
            arguments = string.Format("-i foo.mp4 -i foo.m4a -o \"{0}\"", output);
            psi.Arguments = arguments;
            proc.Start();

            reader = proc.StandardError;
            while ((line = reader.ReadLine()) != null)
            {
                //line += "\n";
                MediaInfo.Text += line;
            }
            proc.WaitForExit();
        }

        /*private void recodingTC(String input, String output)
        {
            Process mkvextract = new Process();
            mkvextract.StartInfo.FileName = "mkvextract";
            mkvextract.StartInfo.Arguments = string.Format("timecodes_v2 \"{0}\" 1:tcv1.txt", input);
            mkvextract.StartInfo.RedirectStandardOutput = true;
            mkvextract.StartInfo.RedirectStandardError = true;
            mkvextract.StartInfo.UseShellExecute = false;
            mkvextract.StartInfo.CreateNoWindow = true;
            mkvextract.Start();
            reader = mkvextract.StandardError;
            while ((line = reader.ReadLine()) != null)
            {
                line += "\n";
                MediaInfo.Text += line;
            }
            mkvextract.WaitForExit();

            Process tctool = new Process();
            tctool.StartInfo.FileName = "tctool";
            tctool.StartInfo.Arguments = "-v 2 tcv1.txt";
            tctool.StartInfo.RedirectStandardOutput = true;
            tctool.StartInfo.RedirectStandardError = true;
            tctool.StartInfo.UseShellExecute = false;
            tctool.StartInfo.CreateNoWindow = true;
            tctool.Start();
            StreamWriter sw = new StreamWriter("tcv2.txt");
            sb.Clear();
            //string sOut = tctool.StandardOutput.ReadToEnd();
            sw.WriteLine(tctool.StandardOutput.ReadToEnd());
            sw.Close();
            tctool.WaitForExit();

            Process timelineeditor = new Process();
            timelineeditor.StartInfo.FileName = "timelineeditor";
            timelineeditor.StartInfo.Arguments = string.Format("--media-timebase 1001 --timecode tcv2.txt \"{0}\" \"{0}.mp4\"", output);
            timelineeditor.StartInfo.RedirectStandardOutput = true;
            timelineeditor.StartInfo.RedirectStandardError = true;
            timelineeditor.StartInfo.UseShellExecute = false;
            timelineeditor.StartInfo.CreateNoWindow = true;
            timelineeditor.Start();
            reader = timelineeditor.StandardError;
            while ((line = reader.ReadLine()) != null)
            {
                line += "\n";
                MediaInfo.Text += line;
            }
            timelineeditor.WaitForExit();
        }*/
        private void MediaInfo_TextChanged(object sender, EventArgs e)
        {
            MediaInfo.SelectionStart = MediaInfo.Text.Length;
            MediaInfo.ScrollToCaret();
        }

        private void fpsCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (fpsCheckBox.Checked) { fpsComboBox.Enabled = true; }
            else { fpsComboBox.Enabled = false; }
        }
    }
}
